﻿using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Geometry;
using System;
using System.Collections;
using System.Collections.Generic;

using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using 纸片人.AttributeUsageFloder;

// https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板

namespace 纸片人.PageViews
{

    [LastModified("2022-5-12", "create OperationDeformation.xaml")]
    [PageType("cpu", "操作变形")]
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class OperationDeformation : Page
    {

        int width = 0, height = 0;

        Color[] source;
        Color[] tempSource;

        List<Point> listPoint = new List<Point>();

        public OperationDeformation()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// 选择图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void select_Click(object sender, RoutedEventArgs e)
        {
            CanvasBitmap bitmap = await Function.SelectImageAsync();

            Function.InitialParameter(bitmap, out width, out height, out source, out tempSource);

        }


        /// <summary>
        /// 查找图像边界
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void findEdge_Click(object sender, RoutedEventArgs e)
        {
            if (source != null)
            {
                listPoint = new List<Point>();



                List<Point> topPoints = new List<Point>();
                List<Point> bottomPoints = new List<Point>();
                List<Point> leftPoints = new List<Point>();
                List<Point> rightPoints = new List<Point>();




            

                //上边点
                for (int x = 0; x < width; x++)
                {
                    for (int y = 0; y < height; y++)
                    {
                        int index = x + y * width;

                        var item = source[x + y * width];

                        if (item.A != 0)
                        {
                            topPoints.Add(new Point(x, y));
                            tempSource[index] = Colors.Red;
                            break;
                        }
                    }
                }

                //下边点
                for (int x = 0; x < width; x++)
                {
                    for (int y = height - 1; y >= 0; y--)
                    {
                        int index = x + y * width;

                        var item = source[x + y * width];
                        if (item.A != 0)
                        {
                            bottomPoints.Add(new Point(x, y));
                            tempSource[index] = Colors.Green;

                            break;
                        }
                    }
                }

                //左边点

                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int index = x + y * width;

                        var item = source[x + y * width];
                        if (item.A != 0)
                        {
                            leftPoints.Add(new Point(x, y));
                            tempSource[index] = Colors.Orange;

                            break;
                        }
                    }
                }

                //右边点
                for (int y = 0; y < height; y++)
                {
                    for (int x = width - 1; x >= 0; x--)
                    {
                        int index = x + y * width;

                      
                        
                        var item = source[x + y * width];
                        if (item.A != 0)
                        {
                            rightPoints.Add(new Point(x, y));
                            tempSource[index] = Colors.Blue;

                            break;
                        }

                      

                    }
                }


                for (int i = 0; i < topPoints.Count; i+=15)
                {
                    var top = topPoints[i];

                    var m = ((double)i / (double)(topPoints.Count - 1));

                    var bottom = bottomPoints[(int)(m * (bottomPoints.Count - 1))];
                    var left = leftPoints[(int)(m * (leftPoints.Count - 1))];
                    var right = rightPoints[(int)(m * (rightPoints.Count - 1))];


                    if (i % 10 == 0)
                    {
                        var tt = topPoints[(int)((m) * (topPoints.Count - 1))];

                        var bb = bottomPoints[(int)((m ) * (bottomPoints.Count - 1))];
                        var rr = rightPoints[(int)((m ) * (rightPoints.Count - 1))];
                        var ll = leftPoints[(int)((m ) * (leftPoints.Count - 1))];


                        //GetCenterPoint(top, bb, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(top, rr, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(top, ll, topPoints, bottomPoints, leftPoints, rightPoints);


                        //GetCenterPoint(left, rr, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(left, bb, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(left, tt, topPoints, bottomPoints, leftPoints, rightPoints);


                        GetCenterPoint(right, tt, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(right, bb, topPoints, bottomPoints, leftPoints, rightPoints);
                        //GetCenterPoint(right, ll, topPoints, bottomPoints, leftPoints, rightPoints);


                        ////GetCenterPoint(bottom, tt, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(bottom, rr, topPoints, bottomPoints, leftPoints, rightPoints);
                        GetCenterPoint(bottom, ll, topPoints, bottomPoints, leftPoints, rightPoints);
                    }






                    listPoint.Add(top);
                    listPoint.Add(bottom);
                    listPoint.Add(left);
                    listPoint.Add(right);
                }


            }
            listPoint = listPoint.DistinctBy(p => new { p.X, p.Y }).ToList();

            var tr = Delaunay.Delaunay1(listPoint);
            if (tr != null)
            {
                foreach (var item in tr)
                {

                    Point p0 = item.Side[0].P0;
                    Point p1 = item.Side[1].P0;
                    Point p2 = item.Side[2].P0;
                    double x = (p0.X + p1.X + p2.X) / 3;
                    double y = (p0.Y + p1.Y + p2.Y) / 3;

                    //listPoint.Add(new Point((p0.X + p1.X) / 2, (p0.Y + p1.Y) / 2));
                    //listPoint.Add(new Point((p0.X + p2.X) / 2, (p0.Y + p2.Y) / 2));
                    //listPoint.Add(new Point((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2));

                    listPoint.Add(new Point(x, y));

                }
            }
            listPoint = listPoint.DistinctBy(p => new { p.X, p.Y }).ToList();

             tr = Delaunay.Delaunay1(listPoint);
            if (tr != null)
            {
                foreach (var item in tr)
                {

                    Point p0 = item.Side[0].P0;
                    Point p1 = item.Side[1].P0;
                    Point p2 = item.Side[2].P0;
                    double x = (p0.X + p1.X + p2.X) / 3;
                    double y = (p0.Y + p1.Y + p2.Y) / 3;

                    //listPoint.Add(new Point((p0.X + p1.X) / 2, (p0.Y + p1.Y) / 2));
                    //listPoint.Add(new Point((p0.X + p2.X) / 2, (p0.Y + p2.Y) / 2));
                    //listPoint.Add(new Point((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2));

                    listPoint.Add(new Point(x, y));

                }
            }
            listPoint = listPoint.DistinctBy(p => new { p.X, p.Y }).ToList();

            canvas.Invalidate();
        }

        void GetCenterPoint(Point lPoint,Point rPoint,List<Point> topPoints, List<Point> bottomPoints, List<Point> leftPoints, List<Point> rightPoints)
        {
            double a = rPoint.X - lPoint.X;
            double b = rPoint.Y - lPoint.Y;

            int x = (int)(lPoint.X + (a / 2));
            int y = (int)(lPoint.Y + b / 2);

            Point tt = topPoints.Find(p => p.X == x);
            Point bb = bottomPoints.Find(p => p.X == x);

            Point ll = leftPoints.Find(p => p.Y == y);
            Point rr = rightPoints.Find(p => p.Y == y);

            if (x > ll.X && x < rr.X && y > tt.Y && y < bb.Y)
            {
                Point point = new Point(x, y);
                listPoint.Add(point);

                //GetCenterPoint(point, lPoint, topPoints, bottomPoints, leftPoints, rightPoints);
                //GetCenterPoint(point, rPoint, topPoints, bottomPoints, leftPoints, rightPoints);

            }



        }


        /// <summary>
        /// 绘制图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void canvas_Draw(Microsoft.Graphics.Canvas.UI.Xaml.CanvasControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasDrawEventArgs args)
        {
            double cw = canvas.ActualWidth;
            double ch = canvas.ActualHeight;

            Vector2 margin = new Vector2((float)(cw - width) / 2f, (float)((ch - height) / 2));

            var tr = Delaunay.Delaunay1(listPoint);


            using (var ds = args.DrawingSession)
            {
                ds.Clear(Colors.Transparent);

                ds.DrawImage(CanvasBitmap.CreateFromColors(canvas, source, width, height), margin);

                ds.DrawImage(CanvasBitmap.CreateFromColors(canvas, tempSource, width, height), margin);

                if (tr != null)
                {
                    foreach (var item in tr)
                    {
                        CanvasPathBuilder path = new CanvasPathBuilder(canvas);


                        path.BeginFigure(item.Side[0].P0.ToVector2() + margin);

                        Point p0 = item.Side[0].P0;
                        Point p1 = item.Side[1].P0;
                        Point p2 = item.Side[2].P0;

                        double x = (p0.X + p1.X + p2.X) / 3;
                        double y = (p0.Y + p1.Y + p2.Y) / 3;


                        if (x < 0 || y < 0)
                        {
                            continue;
                        }

                        //Color c = source[(int)x + (int)y * width];

                        //if (c.A == 0)
                        //{
                        //    continue;
                        //}

                        path.AddLine(item.Side[1].P0.ToVector2() + margin);
                        path.AddLine(item.Side[2].P0.ToVector2() + margin);
                        path.AddLine(item.Side[0].P0.ToVector2() + margin);

                        path.EndFigure(CanvasFigureLoop.Closed);
                        CanvasGeometry cg = CanvasGeometry.CreatePath(path);
                        ds.DrawGeometry(cg, Colors.Black);


                        //ds.DrawCircle(p0.ToVector2() + margin, 1, Colors.Red);
                        //ds.DrawCircle(p1.ToVector2() + margin, 1, Colors.Red);
                        //ds.DrawCircle(p2.ToVector2() + margin, 1, Colors.Red);



                    }

                    foreach (var item in listPoint)
                    {
                        ds.DrawCircle(item.ToVector2() + margin, 1, Colors.Red);

                    }
                }

            }



        }

    }
}

class PointMatric
{


    public int Count { get; set; }
    public List<Point> Points { get; set; } = new List<Point>();



}

public static class MyEnumerableExtensions
{
    public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)

    {

        HashSet<TKey> seenKeys = new HashSet<TKey>();

        foreach (TSource element in source)

        {

            if (seenKeys.Add(keySelector(element)))

            {

                yield return element;

            }

        }

    }
}

